//command.h
#pragma once

//先指定路径名和id，以便后续获取IPC资源唯一标识符

#define PATHNAME "."//假设在当前路径
#define ID 0x66//随便给

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <iostream>
#include <cstring>
#include <cerrno>

//首先获取IPC资源唯一标识符
key_t getKey()
{
    key_t key = ftok(PATHNAME,ID);
    if(key < 0)
    {
        std::cout << "ftok fail:" << strerror(errno) << std::endl;
        exit(1);
    }
    return key;
}

//再创建共享内存
int createShm(key_t key)//需要有key指定
{
    //创建端只希望创建一个新的共享内存
    int shmid = shmget(key,4096,IPC_EXCL | IPC_CREAT | 0600);
    if(shmid < 0)
    {
        std::cout << "shmid fail:" << strerror(errno) << std::endl;
        exit(1);
    }
    return shmid;
}

//非创建端的只需要获取
int getShm(key_t key)
{
    int shmid = shmget(key,4096,IPC_CREAT);
    if(shmid < 0)
    {
        std::cout << "shmid fail:" << strerror(errno) << std::endl;
        exit(1);
    }
    return shmid;
}

//挂接
void* attachShm(int shmid)
{
    void* p = shmat(shmid,nullptr,0);
    //如果挂接失败怎么办？指针类型的p如何转成-1？
    //if((int)p == -1)//这种方法是错误的。因为Linux下的指针为8个字节
    if((long long)p == -1L)
    {
        std::cout << "shmat fail:" << strerror(errno) << std::endl;
        exit(1);
    }
    return p;
}

//去关联
void deAttachShm(const void* shmaddr)
{
    int ret = shmdt(shmaddr);
    if(ret < 0)
    {
        std::cout << "shmcdt fail:" << strerror(errno) << std::endl;
        exit(1);
    }
}

//"删除"共享内存
void delShm(int shmid)
{
    int ret = shmctl(shmid,IPC_RMID,nullptr);
    if(ret < 0)
    {
        std::cout << "shmctl fail:" << strerror(errno) << std::endl;
        exit(1);
    }
}